package service

import (
	"encoding/hex"
	"fmt"
	"hy_808/configor"
	"hy_808/di"
	"hy_808/global"
	"hy_808/logdot"
	"hy_808/protocol/hygprs"
	"hy_808/protocol/jtt808"
	"hy_808/protocol/jtt808/packet/d2p"
	"hy_808/tcpx"
	"log"
	"sync"
	"time"
)

var DeviceEntity = &DeviceService{
	Logger: di.Logdot(),
}

type DeviceService struct {
	sync.Map
	PhoneBusMap sync.Map //key:phone value:busNo
	KeyBusMap   sync.Map //key:any value:busNo
	Logger      *logdot.Logdot
}

func (this *DeviceService) SetDevice(busNo uint32, provinceId, cityId uint16, producerId, deviceId string, deviceModel string, phone string, color byte, card string) *global.DeviceClient {
	tokenCode := ""
	//查询鉴权码
	data, err := GetRowByPhone(phone)
	if err == nil {
		tokenCode = data.TokenCode
	}
	dc := global.DeviceClient{
		BusNo:       busNo,
		DeviceId:    deviceId,
		DeviceModel: deviceModel,
		ProvinceId:  provinceId,
		CityId:      cityId,
		Phone:       phone,
		ProducerId:  producerId,
		Color:       color,
		Card:        card,
		TokenCode:   tokenCode,
		//DeviceSN:    0,
		//AuthCode:    "",
		//JoinHYConn:  nil,
		//Join808Conn: nil,
		//TokenCode: "",
	}
	d := &dc
	this.Store(busNo, d)
	this.PhoneBusMap.Store(phone, busNo)
	conn808 := this.Join808(busNo) //808平台创建tcp连接
	//根据连接地址保存车号
	this.KeyBusMap.Store(conn808.LocalAddr().String(), busNo)
	return d

}

func (this *DeviceService) GetDevice(busNo uint32) *global.DeviceClient {
	v, ok := this.Load(busNo)
	if !ok {
		this.Logger.Error("未找到设备信息", busNo)
		return nil
	}
	dc, _ := v.(*global.DeviceClient)
	return dc
}

// 根据手机号获取设备
func (this *DeviceService) GetDeviceByPhone(phone string) *global.DeviceClient {
	v, ok := this.PhoneBusMap.Load(phone)
	if !ok {
		this.Logger.Error("根据手机号未找到设备", phone)
		return nil
	}
	busNo, _ := v.(uint32)
	v = this.GetDevice(busNo)
	if v != nil {
		dc, _ := v.(*global.DeviceClient)
		return dc
	}
	return nil
}

// 根据连接地址获取终端信息
func (this *DeviceService) GetDeviceByConn(connAddr string) *global.DeviceClient {
	v, ok := this.KeyBusMap.Load(connAddr)
	if !ok {
		this.Logger.Error("根据连接地址未找到设备", connAddr)
		return nil
	}
	busNo, _ := v.(uint32)
	v = this.GetDevice(busNo)
	if v != nil {
		dc, _ := v.(*global.DeviceClient)
		return dc
	}
	return nil
}

func (this *DeviceService) UpdateStatus(busNo uint32) {
	dc := this.GetDevice(busNo)
	if dc == nil {
		dc.Online = true
	}
}

func (this DeviceService) GetHYConn(DdeviceNo uint32) {

}

// 设备连接808平台
func (this *DeviceService) Join808(deviceNo uint32) *tcpx.Conn {
	dc := this.GetDevice(deviceNo)
	ch := make(chan *tcpx.Conn)
	opt := tcpx.Option{
		Name: "Jtt808Client",
		Addr: configor.ConfigGlobal.UpPlatform.Addr,
		//ReadTimeout: 10,
		OnError: func(msg string, err error) {
			log.Println("OnError", msg, err)
		},
		OnRetry: func(retry int, err error) {
			log.Println("OnRetry", retry, err)
		},
		OnConnClosed: func(c *tcpx.Conn) {
			log.Println("OnConnClosed")
		},
		//OnSuccess: func() {
		//	log.Println("OnSuccess")
		//},
		OnConnEstablished: func(c *tcpx.Conn) {
			log.Println("Join808 OnConnEstablished")
			//定时心跳
			ch <- c
		},
		ReceiveProvider: jtt808.ReceiveProvider(Client808.OnReceive),
	}
	go tcpx.StartClient(opt)
	conn := <-ch
	if dc != nil {
		dc.Join808Conn = conn
	}
	return conn
}

func (this *DeviceService) Get808Conn(deviceNo uint32) *tcpx.Conn {
	dc := this.GetDevice(deviceNo)
	if dc != nil {
		return dc.Join808Conn
	}
	return nil
}

func (this *DeviceService) Reg808(busNo uint32) {
	ds := this.GetDevice(busNo)
	if ds != nil {
		register := d2p.GenDeviceRegister(int(ds.ProvinceId), int(ds.CityId), ds.ProducerId, ds.DeviceModel, ds.Phone, ds.DeviceId, ds.Color, ds.Card)
		log.Println("发送注册信息", hex.EncodeToString(register.GetData()))
		this.Get808Conn(busNo).Send(tcpx.MakePackage(register.GetData()))
	}
}

func (this *DeviceService) Auth808(busNo uint32) {
	dc := this.GetDevice(busNo)
	if dc != nil {
		au := d2p.GenAuthenticate(dc.TokenCode)
		log.Println("发送鉴权信息", hex.EncodeToString(au.GetData()))
		this.Get808Conn(busNo).Send(tcpx.MakePackage(au.GetData()))
	}
}

func (this *DeviceService) HeartbeatDC(dc *global.DeviceClient) {
	hb := d2p.GenHeartbeat(dc.Phone)
	fmt.Println("心跳包", hex.EncodeToString(hb.Data))
	dc.Join808Conn.Send(tcpx.MakePackage(hb.Data))
}

func (this *DeviceService) LocationDC(dc *global.DeviceClient, alarmId uint32, hyp hygprs.Fields, attachId byte, attach []byte) {
	lat := hyp.Latitude()
	lon := hyp.Longitude()
	speed := hyp.Speed()
	direct := hyp.Angle()
	lo := d2p.GenLocation(dc.BusNo, dc.Phone, alarmId, d2p.Status, lon, lat, 60, speed, direct, time.Now(), attachId, attach)
	if len(attach) > 0 {
		fmt.Println("位置报警包", hex.EncodeToString(lo.Data))
	}

	dc.Join808Conn.Send(tcpx.MakePackage(lo.Data))
}

func (this *DeviceService) Send808(busNo uint32, data []byte) {
	global.HY808Conn.Send(tcpx.MakePackage(data))
}
